package com.boot.admin.modules.sys.ai.service;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.boot.admin.modules.sys.ai.config.XfyunAiConfig;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.*;

/**
 * 讯飞ASR流式识别服务 - 修复版本
 *
 * @author 李飞洋
 * @date 2025/9/24
 */
@Slf4j
@Service
public class XfyunAsrStreamService {

    private final XfyunAiConfig xfyunAiConfig;
    private final OkHttpClient httpClient;

    // 连接池管理
    private final ConcurrentHashMap<String, AsrWebSocketConnection> connectionPool = new ConcurrentHashMap<>();

    public XfyunAsrStreamService(XfyunAiConfig xfyunAiConfig) {
        this.xfyunAiConfig = xfyunAiConfig;
        this.httpClient = new OkHttpClient.Builder()
                .connectTimeout(15, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
    }

    /**
     * WebSocket流式音频识别 - 使用连接池
     */
    public void recognizeAudioStream(byte[] audioData, RealtimeVoiceService.AsrStreamCallback callback) {
        if (audioData == null || audioData.length == 0) {
            callback.onError("音频数据为空");
            return;
        }

        // 检查音频长度，太短的音频可能无法识别
        if (audioData.length < 1024) { // 小于1KB
            log.debug("音频数据过短，跳过识别: {} bytes", audioData.length);
            callback.onResult("", false);
            return;
        }

        CompletableFuture.runAsync(() -> {
            try {
                // 创建新连接处理这次识别
                createAsrConnection(audioData, callback);
            } catch (Exception e) {
                log.error("创建ASR连接失败", e);
                callback.onError("创建ASR连接失败: " + e.getMessage());
            }
        });
    }

    /**
     * 批量音频识别（兼容性接口）
     */
    public void recognizeAudioBatch(byte[] audioData, RealtimeVoiceService.AsrStreamCallback callback) {
        recognizeAudioStream(audioData, callback);
    }

    /**
     * 创建ASR连接
     */
    private void createAsrConnection(byte[] audioData, RealtimeVoiceService.AsrStreamCallback callback) {
        WebSocket webSocket = null;
        try {
            // 构建WebSocket认证URL
            String authUrl = buildAuthUrl();
            log.debug("建立讯飞ASR连接 - 音频大小: {} bytes", audioData.length);

            // 创建WebSocket连接
            Request request = new Request.Builder()
                    .url(authUrl)
                    .build();

            AsrWebSocketListener listener = new AsrWebSocketListener(audioData, callback);
            webSocket = httpClient.newWebSocket(request, listener);

            // 等待连接建立
            Thread.sleep(100);

        } catch (Exception e) {
            log.error("讯飞ASR WebSocket连接失败", e);
            callback.onError("ASR连接失败: " + e.getMessage());
            if (webSocket != null) {
                webSocket.close(1000, "Connection error");
            }
        }
    }

    /**
     * 构建认证URL
     */
    private String buildAuthUrl() throws Exception {
        // 生成RFC1123格式的时间戳
        SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = sdf.format(new Date());

        // 构建签名原始字符串
        String host = "iat-api.xfyun.cn";
        String requestLine = "GET /v2/iat HTTP/1.1";
        String signatureOrigin = "host: " + host + "\n" + "date: " + date + "\n" + requestLine;

        // 使用HMAC-SHA256计算签名
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec spec = new SecretKeySpec(xfyunAiConfig.getApiSecret().getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(spec);
        byte[] signed = mac.doFinal(signatureOrigin.getBytes(StandardCharsets.UTF_8));
        String signature = Base64Utils.encodeToString(signed);

        // 构建authorization原始字符串
        String authorizationOrigin = String.format(
                "api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                xfyunAiConfig.getApiKey(), "hmac-sha256", "host date request-line", signature
        );

        // Base64编码authorization
        String authorization = Base64Utils.encodeToString(authorizationOrigin.getBytes(StandardCharsets.UTF_8));

        // 构建完整URL
        return String.format("%s?authorization=%s&date=%s&host=%s",
                xfyunAiConfig.getAsrWsUrl(),
                URLEncoder.encode(authorization, StandardCharsets.UTF_8.name()),
                URLEncoder.encode(date, StandardCharsets.UTF_8.name()),
                URLEncoder.encode(host, StandardCharsets.UTF_8.name())
        );
    }

    /**
     * ASR WebSocket监听器 - 修复版本
     */
    private class AsrWebSocketListener extends WebSocketListener {
        private final byte[] audioData;
        private final RealtimeVoiceService.AsrStreamCallback callback;
        private boolean isFirstFrame = true;
        private final StringBuilder resultBuilder = new StringBuilder();
        private String lastSentText = ""; // 新增：记录上次发送的文本，避免重复

        private final ScheduledExecutorService timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
        private ScheduledFuture<?> timeoutTask;

        public AsrWebSocketListener(byte[] audioData, RealtimeVoiceService.AsrStreamCallback callback) {
            this.audioData = audioData;
            this.callback = callback;
        }

        @Override
        public void onOpen(WebSocket webSocket, Response response) {
            log.debug("讯飞ASR WebSocket连接已建立，响应状态: {}", response.code());

            // 设置超时任务：如果30秒内没有收到最终结果，强制完成
            timeoutTask = timeoutExecutor.schedule(() -> {
                log.warn("ASR识别超时，强制发送最终结果");
                String finalResult = resultBuilder.toString().trim();
                callback.onResult(finalResult.isEmpty() ? "" : finalResult, true);
                webSocket.close(1000, "Timeout");
            }, 30, TimeUnit.SECONDS);

            try {
                sendAudioConfig(webSocket);
                sendAudioData(webSocket);
            } catch (Exception e) {
                log.error("发送讯飞ASR配置或音频数据失败", e);
                callback.onError("发送数据失败: " + e.getMessage());
            }
        }

        @Override
        public void onMessage(WebSocket webSocket, String text) {
            log.debug("收到讯飞ASR消息: {}", text);
            try {
                JSONObject response = JSONUtil.parseObj(text);

                // 检查错误
                int code = response.getInt("code", 0);
                if (code != 0) {
                    String message = response.getStr("message", "未知错误");
                    log.error("讯飞ASR返回错误: code={}, message={}", code, message);
                    callback.onError("ASR识别错误: " + message);
                    return;
                }

                // 解析识别结果
                JSONObject data = response.getJSONObject("data");
                if (data != null) {
                    String result = data.getStr("result");
                    int status = data.getInt("status", 0);

                    // 关键修正：处理累积式结果，只发送增量文本
                    if (result != null && !result.trim().isEmpty()) {
                        String recognizedText = parseAsrResult(result);

                        if (recognizedText != null && !recognizedText.trim().isEmpty()) {
                            // 累积到resultBuilder中
                            if (!resultBuilder.toString().contains(recognizedText)) {
                                resultBuilder.append(recognizedText);
                            }

                            String currentFullText = resultBuilder.toString().trim();

                            // 计算增量文本：只发送新增的部分
                            String incrementalText = currentFullText;
                            if (currentFullText.startsWith(lastSentText)) {
                                incrementalText = currentFullText.substring(lastSentText.length()).trim();
                            }

                            // 只有当有新增文本时才发送
                            if (!incrementalText.isEmpty()) {
                                lastSentText = currentFullText; // 更新已发送文本
                                boolean isFinal = (status == 2);
                                callback.onResult(incrementalText, isFinal);

                                log.debug("讯飞ASR增量结果 - 文本: '{}', status: {}, isFinal: {}",
                                        incrementalText, status, isFinal);
                            }
                        }
                    }

                    // 修正：确保在status=2时发送完整的最终结果
                    if (status == 2) {
                        String finalResult = resultBuilder.toString().trim();

                        // 重要：无论是否有累积结果，都发送最终结果
                        if (finalResult.isEmpty()) {
                            // 如果累积结果为空，发送空的最终结果
                            log.info("ASR识别完成，但未识别到内容，发送空的最终结果");
                            callback.onResult("", true);
                        } else {
                            // 发送完整的最终结果
                            log.info("ASR识别完成，最终结果: '{}'", finalResult);
                            callback.onResult(finalResult, true);
                        }

                        webSocket.close(1000, "Recognition complete");
                    }
                }

            } catch (Exception e) {
                log.error("解析讯飞ASR消息失败", e);
                callback.onError("解析ASR响应失败: " + e.getMessage());
            }
        }

        @Override
        public void onFailure(WebSocket webSocket, Throwable t, Response response) {
            String responseInfo = response != null ? "响应状态: " + response.code() : "无响应";
            log.error("讯飞ASR WebSocket连接失败 - {}", responseInfo, t);
            callback.onError("WebSocket连接失败: " + t.getMessage());
        }

        @Override
        public void onClosed(WebSocket webSocket, int code, String reason) {
            log.debug("讯飞ASR WebSocket连接已关闭: {} - {}", code, reason);

            // 取消超时任务
            if (timeoutTask != null && !timeoutTask.isDone()) {
                timeoutTask.cancel(false);
            }

            // 清理资源
            timeoutExecutor.shutdown();
        }

        /**
         * 发送音频配置 - 修复版本
         */
        private void sendAudioConfig(WebSocket webSocket) throws Exception {
            JSONObject config = new JSONObject();

            // 公共参数
            JSONObject common = new JSONObject();
            common.put("app_id", xfyunAiConfig.getAppId());
            config.put("common", common);

            // 业务参数 - 关键修复点
            JSONObject business = new JSONObject();
            business.put("language", "zh_cn");      // 中文
            business.put("domain", "iat");          // 听写领域
            business.put("accent", "mandarin");     // 普通话
            business.put("vinfo", 1);               // 返回详细信息
            business.put("vad_eos", 2000);          // 静音检测时间 2秒
            business.put("dwa", "wpgs");            // 动态修正
            business.put("ptt", 0);                 // 实时传输
            business.put("rlang", "zh-cn");         // 返回语言
            business.put("nunum", 0);               // 将返回结果的数字格式规范为阿拉伯数字
            config.put("business", business);

            // 数据参数（第一帧）
            JSONObject data = new JSONObject();
            data.put("status", 0);  // 第一帧
            data.put("format", "audio/L16;rate=16000");  // 音频格式
            data.put("encoding", "raw");
            data.put("audio", "");  // 第一帧不包含音频数据
            config.put("data", data);

            webSocket.send(config.toString());
            log.debug("发送讯飞ASR配置: {}", config.toString());
        }

        private void sendAudioData(WebSocket webSocket) throws Exception {
            log.debug("开始发送音频数据，总大小: {} bytes", audioData.length);

            int chunkSize = 4096; // 减小chunk size，提高响应速度
            int offset = 0;
            int frameId = 1;

            while (offset < audioData.length) {
                int length = Math.min(chunkSize, audioData.length - offset);
                byte[] chunk = new byte[length];
                System.arraycopy(audioData, offset, chunk, 0, length);

                // 构建音频数据帧
                JSONObject audioFrame = new JSONObject();
                JSONObject data = new JSONObject();
                data.put("status", 1);  // 中间帧
                data.put("format", "audio/L16;rate=16000");
                data.put("encoding", "raw");
                data.put("audio", Base64Utils.encodeToString(chunk));

                audioFrame.put("data", data);
                webSocket.send(audioFrame.toString());

                offset += length;
                frameId++;

                // 减少发送间隔，提高实时性
                Thread.sleep(10);
            }

            // 关键修正：确保结束帧正确发送并等待响应
            JSONObject endFrame = new JSONObject();
            JSONObject endData = new JSONObject();
            endData.put("status", 2);  // 结束帧
            endData.put("format", "audio/L16;rate=16000");
            endData.put("encoding", "raw");
            endData.put("audio", "");  // 空音频数据
            endFrame.put("data", endData);

            webSocket.send(endFrame.toString());
            log.info("发送ASR结束帧，等待最终结果...");

            // 不要立即关闭连接，等待讯飞返回最终结果
            // webSocket会在收到status=2的响应后自动关闭
        }

        /**
         * 解析ASR识别结果 - 修复版本
         */
        private String parseAsrResult(String result) {
            try {
                JSONObject resultObj = JSONUtil.parseObj(result);
                StringBuilder text = new StringBuilder();

                // 讯飞返回的结果格式：{"ws":[{"cw":[{"w":"你好"}]}]}
                if (resultObj.containsKey("ws")) {
                    JSONArray wsArray = resultObj.getJSONArray("ws");
                    for (int i = 0; i < wsArray.size(); i++) {
                        JSONObject wsItem = wsArray.getJSONObject(i);
                        if (wsItem.containsKey("cw")) {
                            JSONArray cwArray = wsItem.getJSONArray("cw");
                            for (int j = 0; j < cwArray.size(); j++) {
                                JSONObject cwItem = cwArray.getJSONObject(j);
                                String w = cwItem.getStr("w");
                                if (w != null && !w.trim().isEmpty()) {
                                    text.append(w);
                                }
                            }
                        }
                    }
                }

                String finalText = text.toString().trim();
                log.debug("解析ASR结果: '{}' -> '{}'", result, finalText);
                return finalText;

            } catch (Exception e) {
                log.warn("解析ASR结果失败，返回原始结果: {}", result, e);
                return "";
            }
        }
    }

    /**
     * WebSocket连接管理
     */
    private static class AsrWebSocketConnection {
        private final WebSocket webSocket;
        private final long createTime;

        public AsrWebSocketConnection(WebSocket webSocket) {
            this.webSocket = webSocket;
            this.createTime = System.currentTimeMillis();
        }

        public WebSocket getWebSocket() { return webSocket; }
        public long getCreateTime() { return createTime; }

        public boolean isExpired(long maxAge) {
            return System.currentTimeMillis() - createTime > maxAge;
        }

        public void close() {
            try {
                webSocket.close(1000, "Connection expired");
            } catch (Exception e) {
                // ignore
            }
        }
    }
}